/*This file is part of WZLibCP.

 *  WZLibCP is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

 *  WZLibCP is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

 *  You should have received a copy of the GNU General Public License
    along with WZLibCP.  If not, see <http://www.gnu.org/licenses/>.
		
	Author: calc0000
*/
#ifndef __WZLIB_WZBINARYREADER_H
#define __WZLIB_WZBINARYREADER_H
#include "WZLibConfig.h"

#include "BinaryReader.h"

namespace WZLib{
	class WZFileHeader;
	/**
	\brief A subclass of BinaryReader that includes specialized routines for
	WZ files.

	WZBinaryReader contains functions to read compressed integers, encrypted strings,
	string blocks, strings at offsets, and offsets.
	*/
	class WZBinaryReader:public BinaryReader{
	public:
		//!Pointer to a WZ file header.  This data is needed for ReadOffset.
		WZFileHeader*	header;
		//Constructors
		/**\brief Constructor that takes an already opened FILE pointer, and uses it to read stuff.

		Make sure fp is not NULL or there will be issues later on.
		\param fp The file pointer to use.
		*/
		ctor			WZBinaryReader(FILE* fp);
		/**\brief Constructor that takes a path to a file (relative or absolute).

		This requires using Close() to close the file pointer.
		\param fPath The path to the file
		*/
		ctor			WZBinaryReader(const char* fPath);
		//Additional readers
		/**\brief Reads a compressed integer from the WZ file.

		Uses the following algorithm:\code
			b = ReadByte()
			if b==-128
				b = ReadInt32()
			return b \endcode
		*/
		int				ReadCompressedInt();
		/**\brief Reads an encrypted string from the WZ file

		Uses the following algorithm:\code
			smallLength = file.readSignedByte()
			if smallLength == 0
				return ""
			retString = ""
			if smallLength >= 0
				mask = 0xAAAA
				if smallLength == 0x7f
					length = file.readInt32()
				else
					length = smallLength
				if length<=0 
					return ""
				for i=0;i<length;i++
					encryptedChar = file.readUInt32()
					encryptedChar ^= mask
					encryptedChar ^= (WzKey[i * 2 + 1] << 8) + WzKey[i * 2]
					retString += encryptedChar
					mask++
			else
				mask = 0xAA
				if smallLength == 0
					length = file.readInt32()
				else
					length = -smallLength
				if length <= 0
					return ""
				for i=0;i<length;i++
					encryptedChar = file.ReadByte()
					encryptedChar ^= mask
					encryptedChar ^= WzKey[i]
					retString += encryptedChar
					mask++
			return retString \endcode
		*/
		std::string		ReadEncryptedString();
		/**\brief Reads a string block from the WZ file.

		Uses the following algorithm: \code
		switch(file.readByte())
			case 0:
			case 0x73:
				return encstring()
			case 1:
			case 0x1B:
				currentOffset = file.tell()
				file.seek(offset)
				retString = ReadEncryptedString()
				file.seek(currentOffset)
				return retString
			default:
				return "" \endcode
		*/
		std::string		ReadStringBlock(long offset);
		/**\brief Reads a string at the specified offset.

		Simply stores the current file position, performs ReadEncryptedString, then restores the file position.
		*/
		std::string		ReadStringAtOffset(long offset);
		/**\brief Reads an encoded offset from the WZ file.

		Uses the following algorithm: \code
			offset=file.tell()
			offset=(offset-wzFile.fileStart)^0xffffffff
			offset*=versionHash
			offset-=0x581c3f6d
			offset=(offset<<(offset&0x1f))|(offset>>(32-offset&0x1F))
			encryptedOffset=file.readUInt32()
			offset^=encryptedOffset
			offset+=wzFile.fileStart*2
			return offset \endcode
		*/
		unsigned int	ReadOffset();
	};
};

#endif